package com.qo.qsdk.pay;

import android.app.Activity;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.ConsumeParams;
import com.android.billingclient.api.ConsumeResponseListener;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesResponseListener;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
import com.android.billingclient.api.SkuDetailsResponseListener;
import com.qo.qsdk.base.IPay;
import com.qo.qsdk.base.IPayConsumeListener;
import com.qo.qsdk.base.IPayExecResultListener;
import com.qo.qsdk.base.IPayListener;
import com.qo.qsdk.base.PayError;
import com.qo.qsdk.base.PayType;

import java.util.ArrayList;
import java.util.List;

public class Pay implements IPay{//}, PurchasesUpdatedListener {

    private static final String TAG = Pay.class.getSimpleName();
    private BillingClient mBillingClient;

    private IPayListener mInitPayListener;
    private IPayListener mPayListener;

    private volatile static Pay INSTANCE;

    public static Pay getInstance() {
        if (INSTANCE == null) {
            synchronized (Pay.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Pay();
                }
            }
        }
        return INSTANCE;
    }

    public Pay() {

    }

    @Override
    public void start(Activity activity, IPayListener iPayListener) {
        mInitPayListener = iPayListener;
    }

    @Override
    public void query(Activity activity) {
        if (getClient(activity).getConnectionState() == BillingClient.ConnectionState.CONNECTED) {
            queryCachePurchases(activity);
            return;
        }
        getClient(activity).startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingServiceDisconnected() {

            }

            @Override
            public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    queryCachePurchases(activity);
                }
            }
        });
    }

    private void queryCachePurchases(Activity activity) {
        getClient(activity).queryPurchasesAsync(BillingClient.SkuType.INAPP, new PurchasesResponseListener() {
            @Override
            public void onQueryPurchasesResponse(@NonNull BillingResult billingResult, @NonNull List<Purchase> list) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null) {
                    for (Purchase purchase : list) {
                        if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
                            notifyServer(true, activity, purchase);
                        }
                    }
                }
            }
        });
    }

    private void notifyServer(boolean isInit, Activity activity, Purchase purchase) {
        IPayListener listener = !isInit ? mPayListener : mInitPayListener;
        if (listener != null) {
            listener.onSuccess(new IPayExecResultListener() {
                @Override
                public void onSuccess(IPayConsumeListener iPayConsumeListener) {
                    ConsumeParams acknowledgePurchaseParams =
                            ConsumeParams.newBuilder()
                                    .setPurchaseToken(purchase.getPurchaseToken())
                                    .build();
                    getClient(activity).consumeAsync(acknowledgePurchaseParams,  new ConsumeResponseListener() {

                        @Override
                        public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
                            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                                Log.e(TAG, "onConsumeResponse,code=BillingResponseCode.OK");
                            } else {
                                //如果消耗不成功，那就再消耗一次
                                Log.e(TAG, "onConsumeResponse=getDebugMessage==" + billingResult.getDebugMessage());
                            }
                            if (iPayConsumeListener != null) {
                                iPayConsumeListener.onSuccess();
                            }
                            mPayListener = null;
                        }
                    });
                }

                @Override
                public void onFail() {
                    mPayListener = null;
                }
            }, PayType.Google, purchase.getAccountIdentifiers().getObfuscatedAccountId(), purchase.getPurchaseToken());
        }
    }

    private void payFail(PayError code, String msg) {
        if (mPayListener != null) {
            mPayListener.onFail(code, msg);
            mPayListener = null;
        }
    }

    @Override
    public void pay(Activity activity, String productId, String orderNo, IPayListener iPayListener) {
        mPayListener = iPayListener;
        getClient(activity).startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingServiceDisconnected() {
                payFail(PayError.NOT_INIT, "google service failed to open");
            }

            @Override
            public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
                if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
                    payFail(PayError.OTHER_ERROR, billingResult.getResponseCode() + ":" + billingResult.getDebugMessage());
                    return;
                }

                List<String> skuList = new ArrayList<>();
                skuList.add(productId);
                SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
                params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
                getClient(activity).querySkuDetailsAsync(
                        params.build(),
                        new SkuDetailsResponseListener() {
                            @Override
                            public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
                                Log.e(TAG, "onSkuDetailsResponse:code=>" + billingResult.getResponseCode() + ",msg:" + billingResult.getDebugMessage());
                                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
                                    //获取商品成功
                                    Log.e(TAG, "获取商品成功");
                                    for (SkuDetails skuDetails : skuDetailsList) {
                                        if (skuDetails.getSku().equals(productId)) {
                                            BillingFlowParams flowParams = BillingFlowParams.newBuilder()
                                                    .setSkuDetails(skuDetails)
                                                    .setObfuscatedAccountId(orderNo)
                                                    .build();
                                            int responseCode = getClient(activity).launchBillingFlow(activity, flowParams).getResponseCode();
                                            if (responseCode != 0) {
                                                if (responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
                                                    //未能購買,正在處理上一筆訂單
                                                    Log.e(TAG, "未能購買,正在處理上一筆訂單");
                                                } else {
                                                    Log.e(TAG, "Current region does not support Google payments");
                                                }
                                            }
                                            return;
                                        }
                                    }
                                }

                                payFail(PayError.OTHER_ERROR, billingResult.getResponseCode() + ":" + billingResult.getDebugMessage());
                            }
                        });
            }
        });
    }

    private BillingClient getClient(Activity activity) {
        if (mBillingClient == null) {
            mBillingClient = BillingClient.newBuilder(activity).enablePendingPurchases().setListener(new PurchasesUpdatedListener() {
                @Override
                public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
                    Log.e(TAG, "onPurchasesUpdated:code=>" + billingResult.getResponseCode() + ",msg:" + billingResult.getDebugMessage());
                    if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
                        Log.e(TAG, "Purchase success");
                        for (Purchase purchase : purchases) {
                            if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
                                notifyServer(false, activity, purchase);
                            }
                        }
                    } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
                        // 处理由用户取消购买流引起的错误
                        Log.e(TAG, "Purchase cancel");
                        if (mPayListener != null) {
                            mPayListener.onCancel();
                            mPayListener = null;
                        }
                    } else {
                        //已存在这个未完成订单，查询订单验证然后消耗掉
//            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) queryCachePurchases();

                        Log.e(TAG, "Pay result error,code=" + billingResult.getResponseCode() + "errorMsg=" + billingResult.getDebugMessage());
                        payFail(PayError.OTHER_ERROR, billingResult.getResponseCode() + ":" + billingResult.getDebugMessage());
                    }
                }
            }).build();
        }
        return mBillingClient;
    }
}
